package edu.polsl.bio.str.manager.logic;

import edu.polsl.bio.str.common.constant.NodeState;
import edu.polsl.bio.str.common.entity.Node;
import edu.polsl.bio.str.common.exception.ManagerException;
import edu.polsl.bio.str.manager.dao.JobDao;
import edu.polsl.bio.str.manager.dao.NodeDao;
import edu.polsl.bio.str.manager.event.NewNodeAttachedEvent;
import edu.polsl.bio.str.manager.messaging.ManagerMessagePublisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * //todo class description
 * <p/>
 * Created on: Jun 14, 2011 11:07:51 AM <br/>
 * <a href="http://www.polsl.pl">www.polsl.pl</a>
 *
 * @author lukasz.olczak@polsl.pl
 */
public class NodeManagementBeanImpl implements NodeManagementBean {
  /**
   * slf4j Logger.
   */
  private static final Logger log = LoggerFactory.getLogger(NodeManagementBeanImpl.class.getName());

  private NodeDao nodeDao;

  private JobDao jobDao;

  private ManagerMessagePublisher managerEventPublisher;

  @Override
  @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
  public long attachNode(String nodeIp, int noTokens) throws Exception {
    log.debug("Attaching node {}", nodeIp);
    Node node = nodeDao.findByIp(nodeIp);
    if (node != null && node.getNodeState().equals(NodeState.ATTACHED)) {
      throw new ManagerException("There is already attached node with ip " + nodeIp);
    }
    if (node != null) {
      node.setLastHeartbeat(new Date());
      node.setTokens(noTokens);
      node.setNoCpu(noTokens);
      node.setNodeState(NodeState.ATTACHED);
      nodeDao.update(node);
    } else {
      node = new Node();
      node.setLastHeartbeat(new Date());
      node.setNodeIp(nodeIp);
      node.setTokens(noTokens);
      node.setNoCpu(noTokens);
      node.setNodeState(NodeState.ATTACHED);
      node = nodeDao.create(node);
    }
    log.info("Attached node {}", node);
    managerEventPublisher.publishEvent(new NewNodeAttachedEvent());
    return node.getId();
  }

  @Override
  @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
  public void detachNode(long nodeId) throws Exception {
    log.debug("Detaching node {}", nodeId);
    Node node = nodeDao.getById(nodeId);
    node.setNodeState(NodeState.DETACHED);
    nodeDao.update(node);
    jobDao.invalidateJobs(nodeId);
  }

  @Override
  @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
  public void heartBeat(long nodeId) throws Exception {
    log.debug("Registering heartbeat for node {}", nodeId);
    Node node = nodeDao.getById(nodeId);
    if (!node.getNodeState().equals(NodeState.ATTACHED)) {
      throw new ManagerException("Node " + nodeId + " is not attached");
    }
    node.setLastHeartbeat(new Date());
    nodeDao.update(node);
  }

  public void setManagerEventPublisher(ManagerMessagePublisher managerEventPublisher) {
    this.managerEventPublisher = managerEventPublisher;
  }

  public void setNodeDao(NodeDao nodeDao) {
    this.nodeDao = nodeDao;
  }

  public void setJobDao(JobDao jobDao) {
    this.jobDao = jobDao;
  }
}
